<template>
  <view class="uploader-container">
    <!-- 上传区域 -->
    <view v-if="showUpload" class="upload-area">
      <wd-upload
        ref="uploadRef"
        :action="uploadAction"
        :headers="uploadHeaders"
        :accept="acceptType"
        :multiple="multiple"
        :max-size="maxSize"
        :max-count="maxCount"
        :file-list="fileList"
        :disabled="disabled"
        :before-upload="beforeUpload"
        @change="handleChange"
        @success="handleSuccess"
        @error="handleError"
        @oversize="handleOversize"
        @exceed="handleExceed"
      >
        <view class="upload-trigger">
          <view class="upload-icon">
            <text class="icon">{{ isVideoMode ? "📹" : "📷" }}</text>
          </view>
          <text class="upload-text">
            {{ isVideoMode ? "上传视频" : "上传图片" }}
          </text>
          <text v-if="tipText" class="upload-tip">{{ tipText }}</text>
        </view>
      </wd-upload>
    </view>

    <!-- 文件预览区域 -->
    <view v-if="fileList.length > 0" class="preview-area">
      <view v-for="(file, index) in fileList" :key="file.uid || index" class="preview-item">
        <!-- 图片预览 -->
        <view v-if="isImage(file)" class="image-preview">
          <image
            :src="file.url || file.path"
            mode="aspectFill"
            class="preview-image"
            @click="previewImage(file, index)"
          />
          <view class="remove-btn" @click.stop="removeFile(index)">
            <text class="remove-icon">×</text>
          </view>
        </view>

        <!-- 视频预览 -->
        <view v-else-if="isVideo(file)" class="video-preview">
          <video
            :src="file.url || file.path"
            class="preview-video"
            :poster="file.poster || ''"
            controls
            @click="previewVideo(file)"
          />
          <view class="remove-btn" @click.stop="removeFile(index)">
            <text class="remove-icon">×</text>
          </view>
          <view v-if="file.duration" class="video-duration">
            {{ formatDuration(file.duration) }}
          </view>
        </view>

        <!-- 上传进度 -->
        <view v-if="file.status === 'uploading'" class="upload-progress">
          <view class="progress-bar">
            <view class="progress-fill" :style="{ width: file.percent + '%' }"></view>
          </view>
          <text class="progress-text">{{ file.percent }}%</text>
        </view>

        <!-- 上传失败 -->
        <view v-if="file.status === 'error'" class="upload-error">
          <text class="error-text">上传失败</text>
          <view class="retry-btn" @click="retryUpload(file)">
            <text>重试</text>
          </view>
        </view>
      </view>
    </view>

    <!-- 切换上传类型按钮 -->
    <view v-if="allowSwitchType" class="type-switch">
      <view class="switch-btn" :class="{ active: !isVideoMode }" @click="switchToImage">图片</view>
      <view class="switch-btn" :class="{ active: isVideoMode }" @click="switchToVideo">视频</view>
    </view>
  </view>
</template>

<script setup lang="ts">
import { ref, computed, watch } from "vue";
import FileAPI from "@/api/file/index";
import { getToken } from "@/utils/cache";

// 定义接口
interface UploadFile {
  uid?: string;
  name: string;
  url?: string;
  path?: string;
  status?: "ready" | "uploading" | "success" | "error";
  percent?: number;
  type?: string;
  size?: number;
  duration?: number;
  poster?: string;
}

interface Props {
  modelValue?: UploadFile[];
  multiple?: boolean;
  maxCount?: number;
  maxSize?: number; // 单位：MB
  acceptType?: "image" | "video" | "all";
  disabled?: boolean;
  showUpload?: boolean;
  allowSwitchType?: boolean;
  tipText?: string;
}

interface Emits {
  (e: "update:modelValue", files: UploadFile[]): void;
  (e: "change", files: UploadFile[]): void;
  (e: "success", file: UploadFile, files: UploadFile[]): void;
  (e: "error", error: any, file: UploadFile): void;
  (e: "remove", file: UploadFile, index: number): void;
}

// Props 定义
const props = withDefaults(defineProps<Props>(), {
  modelValue: () => [],
  multiple: true,
  maxCount: 9,
  maxSize: 50, // 默认50MB
  acceptType: "all",
  disabled: false,
  showUpload: true,
  allowSwitchType: false,
  tipText: "",
});

// Emits 定义
const emit = defineEmits<Emits>();

// 响应式数据
const fileList = ref<UploadFile[]>([...props.modelValue]);
const isVideoMode = ref(false);
const uploadRef = ref();

// 计算属性
const uploadAction = computed(() => FileAPI.uploadUrl);
const uploadHeaders = computed(() => ({
  Authorization: getToken() ? `Bearer ${getToken()}` : "",
}));

// 监听modelValue变化
watch(
  () => props.modelValue,
  (newVal) => {
    fileList.value = [...newVal];
  },
  { deep: true }
);

// 监听fileList变化
watch(
  fileList,
  (newVal) => {
    emit("update:modelValue", newVal);
    emit("change", newVal);
  },
  { deep: true }
);

// 工具函数
const isImage = (file: UploadFile): boolean => {
  const type = file.type || "";
  return type.startsWith("image/") || /\.(jpg|jpeg|png|gif|bmp|webp)$/i.test(file.name);
};

const isVideo = (file: UploadFile): boolean => {
  const type = file.type || "";
  return type.startsWith("video/") || /\.(mp4|avi|mov|wmv|flv|mkv|3gp)$/i.test(file.name);
};

const formatDuration = (seconds: number): string => {
  const mins = Math.floor(seconds / 60);
  const secs = Math.floor(seconds % 60);
  return `${mins}:${secs.toString().padStart(2, "0")}`;
};

// 上传前检查
const beforeUpload = (file: any): boolean => {
  const fileType = file.type || "";
  const fileName = file.name || "";

  // 检查文件类型
  if (props.acceptType === "image" && !isImage({ type: fileType, name: fileName })) {
    uni.showToast({
      title: "请选择图片文件",
      icon: "none",
    });
    return false;
  }

  if (props.acceptType === "video" && !isVideo({ type: fileType, name: fileName })) {
    uni.showToast({
      title: "请选择视频文件",
      icon: "none",
    });
    return false;
  }

  // 检查文件大小
  const fileSizeMB = file.size / 1024 / 1024;
  if (fileSizeMB > props.maxSize) {
    uni.showToast({
      title: `文件大小不能超过${props.maxSize}MB`,
      icon: "none",
    });
    return false;
  }

  return true;
};

// 事件处理
const handleChange = (files: any[]) => {
  fileList.value = files.map((file) => ({
    ...file,
    status: file.status || "ready",
    percent: file.percent || 0,
  }));
};

const handleSuccess = (response: any, file: any) => {
  const index = fileList.value.findIndex((f) => f.uid === file.uid);
  if (index !== -1) {
    fileList.value[index] = {
      ...fileList.value[index],
      url: response.data?.url || response.url,
      status: "success",
      percent: 100,
    };
    emit("success", fileList.value[index], fileList.value);
  }
};

const handleError = (error: any, file: any) => {
  const index = fileList.value.findIndex((f) => f.uid === file.uid);
  if (index !== -1) {
    fileList.value[index].status = "error";
    emit("error", error, fileList.value[index]);
  }
};

const handleOversize = (file: any) => {
  uni.showToast({
    title: `文件大小不能超过${props.maxSize}MB`,
    icon: "none",
  });
};

const handleExceed = () => {
  uni.showToast({
    title: `最多只能上传${props.maxCount}个文件`,
    icon: "none",
  });
};

const removeFile = (index: number) => {
  const removedFile = fileList.value[index];
  fileList.value.splice(index, 1);
  emit("remove", removedFile, index);
};

const retryUpload = (file: UploadFile) => {
  if (uploadRef.value) {
    uploadRef.value.upload();
  }
};

const previewImage = (file: UploadFile, index: number) => {
  const images = fileList.value.filter((f) => isImage(f)).map((f) => f.url || f.path);
  const currentIndex = images.findIndex((url) => url === (file.url || file.path));

  uni.previewImage({
    urls: images,
    current: currentIndex,
  });
};

const previewVideo = (file: UploadFile) => {
  uni.navigateTo({
    url: `/pages/common/video-preview?url=${encodeURIComponent(file.url || file.path || "")}`,
  });
};

const switchToImage = () => {
  isVideoMode.value = false;
};

const switchToVideo = () => {
  isVideoMode.value = true;
};

// 暴露方法
const clearFiles = () => {
  fileList.value = [];
};

const getFiles = () => fileList.value;

// 暴露给父组件
defineExpose({
  clearFiles,
  getFiles,
});
</script>

<style lang="scss" scoped>
.uploader-container {
  width: 100%;
}

.upload-area {
  margin-bottom: 20rpx;
}

.upload-trigger {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 160rpx;
  height: 160rpx;
  border: 2rpx dashed #d9d9d9;
  border-radius: 8rpx;
  background-color: #fafafa;
  transition: all 0.3s ease;
}

.upload-trigger:hover {
  border-color: #40a9ff;
  background-color: #f6ffed;
}

.upload-icon {
  margin-bottom: 8rpx;
}

.icon {
  font-size: 48rpx;
  color: #999;
}

.upload-text {
  font-size: 24rpx;
  color: #666;
  margin-bottom: 4rpx;
}

.upload-tip {
  font-size: 20rpx;
  color: #999;
}

.preview-area {
  display: flex;
  flex-wrap: wrap;
  gap: 20rpx;
}

.preview-item {
  position: relative;
  width: 160rpx;
  height: 160rpx;
  border-radius: 8rpx;
  overflow: hidden;
}

.image-preview,
.video-preview {
  position: relative;
  width: 100%;
  height: 100%;
}

.preview-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.preview-video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.remove-btn {
  position: absolute;
  top: 8rpx;
  right: 8rpx;
  width: 40rpx;
  height: 40rpx;
  background-color: rgba(0, 0, 0, 0.6);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 10;
}

.remove-icon {
  color: #fff;
  font-size: 24rpx;
  line-height: 1;
}

.video-duration {
  position: absolute;
  bottom: 8rpx;
  right: 8rpx;
  padding: 4rpx 8rpx;
  background-color: rgba(0, 0, 0, 0.6);
  color: #fff;
  font-size: 20rpx;
  border-radius: 4rpx;
}

.upload-progress {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.progress-bar {
  width: 80%;
  height: 8rpx;
  background-color: rgba(255, 255, 255, 0.3);
  border-radius: 4rpx;
  overflow: hidden;
  margin-bottom: 8rpx;
}

.progress-fill {
  height: 100%;
  background-color: #52c41a;
  transition: width 0.3s ease;
}

.progress-text {
  color: #fff;
  font-size: 24rpx;
}

.upload-error {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.7);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.error-text {
  color: #ff4d4f;
  font-size: 24rpx;
  margin-bottom: 8rpx;
}

.retry-btn {
  padding: 4rpx 8rpx;
  background-color: #1890ff;
  color: #fff;
  font-size: 20rpx;
  border-radius: 4rpx;
}

.type-switch {
  display: flex;
  gap: 20rpx;
  margin-bottom: 20rpx;
}

.switch-btn {
  padding: 12rpx 24rpx;
  border: 2rpx solid #d9d9d9;
  border-radius: 8rpx;
  font-size: 28rpx;
  color: #666;
  transition: all 0.3s ease;
}

.switch-btn.active {
  border-color: #1890ff;
  color: #1890ff;
  background-color: #e6f7ff;
}
</style>
